package com.example.springbootjwtexample.koal;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.RandomStringUtils;

import java.io.UnsupportedEncodingException;
import java.net.ProtocolException;
import java.util.HashMap;
import java.util.Map;

public class SSORequest {

    //未经解析的原始数据
    private String header;
    private String payload;
    private String secret;

    //解析后的认证头数据
    private String version;
    private String algorithm;
    private String timestamp;
    private String nonce;
    private String aid;

    //不参与传输的内部数据
    private String akey;

    public SSORequest() {
    }

    public SSORequest(Map<String,Object> head,Map<String,Object> payload, String aid, String akey) throws UnsupportedEncodingException {
        super();
        this.payload = ByteUtil.base64UrlEncode(JSONObject.toJSONString(payload).getBytes("UTF-8"));
        this.version = "a1";
        this.nonce = RandomStringUtils.randomNumeric(16);
        this.aid = aid;
        this.akey = akey;
        this.algorithm = "HS256";
        this.timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String header = generateHeader(head,aid);
        this.header = header;
        this.secret = generateSecret(akey, header, this.payload);
    }

    public SSORequest(Map<String,Object> payload, String aid, String akey) throws UnsupportedEncodingException {
        super();
        this.payload = ByteUtil.base64UrlEncode(JSONObject.toJSONString(payload).getBytes("UTF-8"));
        this.version = "a1";
        this.nonce = RandomStringUtils.randomNumeric(16);
        this.aid = aid;
        this.akey = akey;
        this.algorithm = "HS256";
        this.timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String header = generateHeader(version, aid, nonce, algorithm, timestamp);
        this.header = header;
        this.secret = generateSecret(akey, header, this.payload);
    }

    public SSORequest(String payload, String version, String nonce, String aid, String akey, String algorithm, String timestamp) throws UnsupportedEncodingException {
        super();

        this.payload = ByteUtil.base64UrlEncode(payload.getBytes("UTF-8"));
        this.version = version;
        this.nonce = nonce;
        this.aid = aid;
        this.akey = akey;
        this.algorithm = algorithm;
        this.timestamp = timestamp;
        String header = generateHeader(version, aid, nonce, algorithm, timestamp);
        this.header = header;
        this.secret = generateSecret(akey, header, this.payload);
    }

    public SSORequest(String header, String payload, String secret, String version, String alg, String timestamp,
                      String nonce, String aid, String akey) {
        super();
        this.header = header;
        this.payload = payload;
        this.secret = secret;
        this.version = version;
        this.algorithm = alg;
        this.timestamp = timestamp;
        this.nonce = nonce;
        this.aid = aid;
        this.akey = akey;
    }

    private String generateSecret(String akey, String header, String payload) {
        String secret = ByteUtil.base64UrlEncode(EncryptUtil.SHA256HMACforString(akey, header + '.' + payload));
        return secret;
    }

    public void verifySecret(String akey, String header, String payload) throws ProtocolException {
        String secretTemp = generateSecret(akey, header, payload);
        if (!secretTemp.equals(this.secret)) {
            throw new ProtocolException("验证不正确");
        }
    }

    public boolean verifySecret() {
        String secretTemp = generateSecret(akey, header, payload);
        if (!secretTemp.equals(this.secret)) {
            return false;
        }
        return true;
    }

    private String generateHeader(String version, String aid, String nonce, String algorithm, String timestamp) throws UnsupportedEncodingException, UnsupportedEncodingException {
        HashMap<String, String> m = new HashMap<>();
        m.put("v", version);
        m.put("alg", algorithm);
        m.put("aid", aid);
        m.put("timestamp", timestamp);
        m.put("nonce", nonce);
        return ByteUtil.base64UrlEncode(JSONObject.toJSONString(m).getBytes("UTF-8"));
    }

    private String generateHeader(Map<String,Object> map,String aid) throws UnsupportedEncodingException, UnsupportedEncodingException {
        HashMap<String, Object> m = new HashMap<>();
        m.put("v", "a1");
        m.put("alg", "HS256");
        m.put("aid", aid);
        m.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        m.put("nonce", RandomStringUtils.randomNumeric(16));
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            m.putIfAbsent(key,value);
        }
        return ByteUtil.base64UrlEncode(JSONObject.toJSONString(m).getBytes("UTF-8"));
    }

    public String toString() {
        return this.header + "." + this.payload + "." + this.secret;
    }

    public String getSecret() {
        return secret;
    }

    public String getHeader() {
        return header;
    }

    public String getPayload() {
        return payload;
    }

    public String getVersion() {
        return version;
    }

    public String getAlgorithm() {
        return algorithm;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public String getAid() {
        return aid;
    }

    public String getNonce() {
        return nonce;
    }

}
